/*******************************************************************************
 * Copyright (c) 2011 Olexandr V. Shaposhnikov.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Olexandr V. Shaposhnikov - initial API and implementation and/or initial documentation
 *******************************************************************************/
package com.funkyroach.use.core.mixin;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.ElementChangedEvent;
import org.eclipse.dltk.core.IElementChangedListener;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.IShutdownListener;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.core.mixin.IMixinElement;
import org.eclipse.dltk.core.mixin.MixinModel;
import org.eclipse.dltk.internal.core.SourceMethod;
import org.eclipse.dltk.internal.core.SourceType;

import com.funkyroach.use.core.language.USLanguageToolkit;
import com.funkyroach.use.plugin.USPlugin;

public class USMixinModel implements IShutdownListener,
		IElementChangedListener, IResourceChangeListener {

	public static final String MIXIN_ARGUMENT_PREFIX = "ARGUMENT.";
	public static final String MIXIN_METHOD_PREFIX = "METHOD.";
	public static final String MIXIN_CLASS_PREFIX = "CLASS.";
	public static final String MIXIN_MODULE_PREFIX = "MODULE.";
	public static final String MIXIN_VARIABLE_PREFIX = "VAR.";
	public static final String MIXIN_SCOPE_SEPARATOR = "{";

	private static final Map<IScriptProject, USMixinModel> s_Instances = new HashMap<IScriptProject, USMixinModel>();

	public static synchronized USMixinModel instance(IScriptProject project) {
		Assert.isNotNull(project);
		synchronized (s_Instances) {
			USMixinModel mixinModel = s_Instances.get(project);
			if (mixinModel == null) {
				mixinModel = new USMixinModel(project);
				s_Instances.put(project, mixinModel);
			}
			return mixinModel;
		}
	}

	private final MixinModel model;

	private USMixinModel(IScriptProject project) {
		model = new MixinModel(USLanguageToolkit.getDefault(), project);
		USPlugin.instance().addShutdownListener(this);

		DLTKCore.addElementChangedListener(this,
				ElementChangedEvent.POST_CHANGE);
		ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
	}

	public IMixinElement get(String key) {
		return model.get(key);
	}

	public void clear() {
		model.clearKeysCache();
	}

	@Override
	public void shutdown() {
		DLTKCore.removeElementChangedListener(this);
		ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
		model.stop();
	}

	public MixinModel getRawModel() {
		return model;
	}

	public SourceType findClass(final String className) {
		ISourceModule sourceModule = findModule(className);
		if(sourceModule != null) {
			return  (SourceType) sourceModule.getType(className);
		}
		return null;
	}

	public SourceMethod findMetod(final String className,
			final String methodName) {
		IMixinElement[] result = model.find(className,
				new NullProgressMonitor());
		if (result.length > 0)
			return (SourceMethod) result[0];
		return null;
	}

	public ISourceModule findModule(String name) {
		ISourceModule[] result = model.findModules(MIXIN_MODULE_PREFIX + name);
		if (result.length > 0) {
			return result[0];
		}
		return null;
	}

	@Override
	public void resourceChanged(IResourceChangeEvent event) {
	//	System.out.println(event);
	}

	@Override
	public void elementChanged(ElementChangedEvent event) {
		//System.out.println(event);
	}
}
